<template>
  <div class="bill-classifier">
    <h1>饮食类-智能账单分类录入器</h1>
    <div class="input-group">
      <label for="amount">金额(元)：</label>
      <input type="number" id="amount" v-model="amount" placeholder="请输入金额" required />
      <p v-if="errors.amount" class="error">{{ errors.amount }}</p>
    </div>
    <div class="input-group">
      <label for="time">交易时间：</label>
      <input type="datetime-local" id="time" v-model="time" required />
      <p v-if="errors.time" class="error">{{ errors.time }}</p>
    </div>
    <div class="input-group">
      <label for="billType">物品描述：</label>
      <input type="text" id="billType" v-model="billType" placeholder="请输入物品描述" required />
      <p v-if="errors.billType" class="error">{{ errors.billType }}</p>
    </div>
    <!-- 将上传文件按钮和预测录入按钮放在同一行 -->
    <div class="button-group">
      <el-upload :action="uploadAction" :before-upload="beforeUpload" :on-change="handleFileChange"
        :show-file-list="false" :http-request="handleFileUpload">
        <el-button class="upload-button" type="primary">上传账单 / 自动录入</el-button>
      </el-upload>
      <button @click="predict">预测 / 录入</button>
    </div>

    <!-- 新增的账单数据展示容器 -->
    <div v-if="billData.length > 0" class="bill-data-container">
      <h2>上传的账单数据：</h2>
      <div class="bill-data-scroll">
        <ul>
          <li v-for="(bill, index) in billData" :key="index">
            <p>金额: {{ bill.amount }}</p>
            <p>交易时间: {{ bill.transactionTime }}</p>
            <p>商品: {{ bill.product }}</p>
          </li>
        </ul>
      </div>
    </div>

    <div v-if="predictions" class="results">
      <h2 style="font-size: 25px;">预测结果：</h2>
      <p style="font-size: 18px;">此类账单应该为：<strong>{{ predictedCategory }}</strong></p>
      <p style="font-size: 18px;">各类别概率：</p>
      <ul>
        <li v-for="(probability, category) in predictions" :key="category">
          {{ category }}: {{ (probability * 100).toFixed(2) }}%
        </li>
      </ul>
    </div>

    <!-- 仪表盘容器 -->
    <div ref="gaugeChart" class="gauge-chart"></div>
  </div>
</template>

<script>
import axios from 'axios';
import moment from 'moment';
import { Message } from 'element-ui';
import * as echarts from 'echarts'; // 引入 ECharts

export default {
  name: 'BillClassifier',
  data() {
    return {
      uploadAction: 'http://localhost:8080/upload', // 添加上传接口地址
      amount: '',
      time: '',
      billType: '',
      predictions: null,
      predictedCategory: '',
      errors: {
        amount: '',
        time: '',
        billType: '',
      },
      allConsumeList: [],
      gaugeChart: null, // 用于存储 ECharts 实例
      billData: [], // 新增：用于存储上传的账单数据
      currentIndex: 0, // 新增：用于跟踪当前提取的数据索引
      processingInterval: null // 新增：保存定时器ID
    };
  },
  mounted() {
    // 初始化仪表盘
    this.initGaugeChart();
    // 获取消费类型列表
    axios.get('/consumptionType/query', {
      params: {
        houseId: sessionStorage.getItem('houseId'),
      }
    }).then((res) => {
      if (res.data.description === 'success') {
        this.allConsumeList = res.data.data;
      }
    });
  },
  methods: {
    // 自定义文件上传处理
    handleFileUpload(file) {
      const reader = new FileReader();
      reader.onload = (e) => {

        this.processCSVFile(e.target.result);
      };
      reader.readAsArrayBuffer(file.file);
    },
    // 文件上传前的校验
    beforeUpload(file) {
      const isCSV = file.type === 'text/csv';
      if (!isCSV) {
        Message.error('只能上传 CSV 文件！');
      }
      return isCSV;
    },
    // 处理文件变化
    handleFileChange(file, fileList) {
      console.log('文件变化:', file, fileList);
    },
    // 处理 CSV 文件
    // 在 methods 部分找到 processCSVFile 方法并替换为以下代码
    processCSVFile(csvText) {
      let csvString;
      if (csvText instanceof ArrayBuffer) {
        const decoder = new TextDecoder('utf-8');
        csvString = decoder.decode(csvText);
      } else if (typeof csvText === 'string') {
        csvString = csvText;
      } else {
        console.error('Invalid CSV data:', csvText);
        return;
      }

      if (csvString.charCodeAt(0) === 0xFEFF) {
        csvString = csvString.slice(1);
      }

      const lines = csvString.split('\n').filter(line => line.trim() !== '');


      const fieldMapping = {
        '交易时间': ['交易时间', '下单时间', '付款时间', 'time', 'transaction_time'],
        '商品': ['商品', '商品名称', '物品', 'product', 'item'],
        '金额(元)': ['金额(元)', '价格(元)', '金额', 'price', 'cost']
      };

      let headerIndex = -1;


      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        const headers = line.split(',').map(h => h.trim().replace(/^"|"$/g, ''));
        const matchedFields = headers.map((header, index) => {
          for (const [canonicalName, aliases] of Object.entries(fieldMapping)) {
            if (aliases.includes(header)) {
              return { canonicalName, index };
            }
          }
          return null;
        }).filter(item => item !== null);

        if (matchedFields.length >= 3) { // 确保至少有三个字段匹配
          headerIndex = i;

          // 将原始表头替换成标准字段名
          this.headerMap = {};
          matchedFields.forEach(({ canonicalName, index }) => {
            this.headerMap[canonicalName] = index;
          });
          break;
        }
      }

      if (headerIndex === -1) {
        console.error('无法识别CSV文件表头');
        Message.error('CSV文件格式不正确，请检查文件内容');
        return;
      }

      this.billData = lines.slice(headerIndex + 1).map(row => {
        const values = row.split(',').map(v => v.trim().replace(/^"|"$/g, ''));
        const bill = {};
        Object.keys(fieldMapping).forEach(canonicalName => {
          const index = this.headerMap[canonicalName];
          if (index !== undefined) {
            bill[canonicalName] = values[index] || '';
          }
        });
        return {
          amount: bill['金额(元)'] || '',
          product: bill['商品'] || '',
          transactionTime: bill['交易时间'] || ''
        };
      });
      console.log('Parsed CSV data:', this.billData);

      if (this.billData.length > 0) {
        Message.success('CSV文件解析成功，开始自动处理...');

        // 启动定时任务
        if (this.processingInterval) {
          clearInterval(this.processingInterval); // 清除之前的定时器
        }

        this.currentIndex = 0;

        this.processingInterval = setInterval(() => {
          if (this.currentIndex < this.billData.length) {
            const bill = this.billData[this.currentIndex];

            this.amount = parseFloat(bill.amount.replace(/[^0-9.-]/g, ''));
            this.time = moment(bill.transactionTime, 'YYYY/MM/DD HH:mm').format('YYYY-MM-DDTHH:mm');
            this.billType = bill.product;

            this.predict(); // 调用预测方法

            // 从数组中移除当前处理的数据项
            this.billData.splice(this.currentIndex, 1);
          } else {
            clearInterval(this.processingInterval);
            this.processingInterval = null;
            Message.success('所有数据已处理完成');
          }
        }, 7000); // 每 7 秒处理一条数据
      } else {
        Message.warning('CSV文件未包含有效数据');
      }
    },
    // 初始化仪表盘
    initGaugeChart() {
      const chartDom = this.$refs.gaugeChart;
      this.gaugeChart = echarts.init(chartDom);
      const option = {
        series: [
          {
            type: 'gauge',
            startAngle: 180,
            endAngle: 0,
            center: ['50%', '50%'],
            radius: '80%',
            min: 0,
            max: 1,
            splitNumber: 8,
            axisLine: {
              lineStyle: {
                width: 6,
                color: [
                  [0.25, '#FF6E76'],
                  [0.5, '#FDDD60'],
                  [0.75, '#58D9F9'],
                  [1, '#7CFFB2']
                ]
              }
            },
            pointer: {
              icon: 'path://M200,5 L200,45 L400,45 L400,60 L200,60 z', // 细长指针形状
              length: '80%', // 指针长度
              width: 5, // 指针宽度
              offsetCenter: [0, '-40%'], // 指针位置偏移
              itemStyle: {
                color: 'auto'
              }
            },
            axisTick: {
              length: 12,
              lineStyle: {
                color: 'auto',
                width: 2
              }
            },
            splitLine: {
              length: 20,
              lineStyle: {
                color: 'auto',
                width: 5
              }
            },
            axisLabel: {
              color: '#464646',
              fontSize: 20,
              distance: -60,
              rotate: 'tangential',
              formatter: function (value) {
                if (value === 0.875) {
                  return '等级 A';
                } else if (value === 0.625) {
                  return '等级 B';
                } else if (value === 0.375) {
                  return '等级 C';
                } else if (value === 0.125) {
                  return '等级 D';
                }
                return '';
              }
            },
            title: {
              offsetCenter: [0, '-20%'],
              fontSize: 20
            },
            detail: {
              backgroundColor: 'transparent', // 背景透明
              borderColor: 'transparent', // 边框透明
              borderWidth: 0,
              borderRadius: 0,
              fontWeight: 'bolder',
              fontSize: 30,
              offsetCenter: [0, '50%'], // 详细信息位置
              valueAnimation: true,
              formatter: function (value) {
                // 根据 value 计算具体的评分值
                const score = Math.round(value * 100);
                return `${score}分`;
              },
              color: 'inherit'
            },
            data: [
              {
                value: 0, // 初始值为 0
                name: '预测等级评定'
              }
            ]
          }
        ]
      };
      this.gaugeChart.setOption(option);
    },
    // 更新仪表盘
    updateGaugeChart(value) {
      if (this.gaugeChart) {
        this.gaugeChart.setOption({
          series: [
            {
              data: [
                {
                  value: value,
                  name: 'Grade Rating'
                }
              ]
            }
          ]
        });
      }
    },
    async predict() {
      // 清除之前的错误信息
      this.errors = {
        amount: '',
        time: '',
        billType: '',
      };

      // 验证所有输入框是否为空
      let isValid = true;
      if (!this.amount) {
        this.errors.amount = '请输入金额';
        isValid = false;
      }
      if (!this.time) {
        this.errors.time = '请输入时间';
        isValid = false;
      }
      if (!this.billType) {
        this.errors.billType = '请输入物品名';
        isValid = false;
      }

      if (!isValid) {
        return;
      }

      try {
        // 只发送 billType 的值
        const data = [this.billType];
        console.log('发送的数据：', data);
        const response = await axios.post('http://localhost:8080/bills/predict', data);
        console.log('预测结果：', response.data);
        this.predictions = response.data;

        // 找到概率最大的类别
        let maxProbability = 0;
        for (const [category, probability] of Object.entries(this.predictions)) {
          if (probability > maxProbability) {
            maxProbability = probability;
            this.predictedCategory = category;
          }
        }

        // 更新仪表盘
        this.updateGaugeChart(maxProbability);

        // 调用录入方法
        this.record();
      } catch (error) {
        console.error('预测失败：', error);
        alert('预测失败，请稍后重试！');
      }
    },

    async record() {
      if (!this.predictedCategory) {
        alert('请先进行预测！');
        return;
      }

      // 获取消费类型的 id
      const consumptionId = this.allConsumeList.find(item => item.name === this.predictedCategory)?.id;
      if (!consumptionId) {
        alert('未找到对应的消费类型！');
        return;
      }

      const params = {
        userId: sessionStorage.getItem('userId'),
        houseId: sessionStorage.getItem('houseId'),
        consumptionId: consumptionId, // 使用消费类型的 id
        billType: '1', // 账单类型永远为支出
        money: this.amount,
        remark: this.billType, // 物品描述作为备注
        recordTime: moment(this.time).format('YYYY-MM-DD HH:mm:ss'), // 使用 moment 格式化时间
        inputMethod: '1', // 默认设置录入方式为1
      };
      console.log('请求参数：', params);
      try {
        const response = await axios.post('/bill/add', params);
        if (response.data.description === 'success') {
          // 使用 Message 组件显示成功弹框
          Message.success({
            message: `此账单自动录入成功！录入类型：${this.predictedCategory}`,
            duration: 6000, // 弹框显示时间（毫秒）
            onClose: () => {
              // 在消息框关闭后清空预测的类型和概率信息
              // 以及清空输入框
              this.amount = '';
              this.time = '';
              this.billType = '';
              this.predictedCategory = '';
              this.predictions = null;
              // 重置仪表盘
              this.updateGaugeChart(0);
            }
          });

        } else {
          alert('账单录入失败，请稍后重试！');
        }
      } catch (error) {
        console.error('录入失败：', error);
        alert('录入失败，请稍后重试！');
      }
    }
  }
};
</script>

<style scoped>
.bill-classifier {
  max-width: 700px;
  /* 缩短整体宽度 */
  margin: 0 auto;
  padding: 20px;
  text-align: center;
}

.bill-data-container {
  margin-top: -260px;
  margin-left: -300px;
  padding: 10px;
  border: 1px solid #565555;
  border-radius: 8px;
  background-color: #f9f9f9 0.2;
  text-align: left;
  max-height: 300px;
  overflow: hidden;
  /* 隐藏超出部分 */
  max-width: 350px;
}

.bill-data-scroll {
  max-height: 200px;
  overflow-y: auto;
  /* 启用垂直滚动条 */
}

.bill-data-container h2 {
  font-size: 13px;
  margin-bottom: 8px;
}

.bill-data-container ul {
  list-style-type: none;
  padding: 0;
}

.bill-data-container li {
  margin-bottom: 10px;
  padding: 5px;
  border-bottom: 1px solid #4f4e4e;
}

.bill-data-container li:last-child {
  border-bottom: none;
}

.bill-data-container p {
  margin: 3px 0;
  font-size: 9px;
}

.input-group {
  margin-bottom: 15px;
}

label {
  display: block;
  margin-bottom: 8px;
  font-weight: bold;
}

input {
  width: 70%;
  padding: 8px;
  box-sizing: border-box;
}

.button-group {
  margin-top: 15px;
  display: flex;
  justify-content: center;
  gap: 20px;
  /* 设置按钮之间的间距 */
}

.button-group button {
  padding: 8px 20px;
  background-color: #42b983;
  color: white;
  border: none;
  cursor: pointer;
  font-size: 16px;
  border-radius: 10px;
}

.button-group button:hover {
  background-color: #3aa876;
}

.results {
  margin-top: 0;
  margin-left: 0;
  text-align: left;
  line-height: 35px;
  position: absolute;
  bottom: 100px;
  left: 260px;
  z-index: 10;
}

ul {
  list-style-type: none;
  padding: 0;
}

li {
  margin-right: 10px;
  /* 设置间距 */
  display: inline-block;
}

.error {
  color: red;
  font-size: 12px;
  margin-top: 5px;
}

.bill-classifier h1 {
  font-size: 30px;
  /* 加大字体 */
  font-weight: bold;
  /* 加粗字体 */
  margin-bottom: 30px;
  /* 保持居中对齐 */
  text-align: center;
}

.gauge-chart {
  width: 400px;
  height: 400px;
  position: absolute;
  right: 100px;
  bottom: -100px;
}

.upload-button {
  height: 40px;
}
</style>